package com.xiongmao.webflux.auth.service.impl;

import com.xiongmao.webflux.auth.service.FileService;
import com.xiongmao.webflux.common.ResponseData;
import com.xiongmao.webflux.common.language.ErrorMsgEnum;
import com.xiongmao.webflux.common.sftp.FileConfig;
import com.xiongmao.webflux.common.sftp.FileSystemServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ZeroCopyHttpOutputMessage;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

/**
 * @Author: lao_hu
 * @Date: 2022/2/25 15:17
 * @Description:
 */
@Service
public class FileServiceImpl implements FileService {
    @Autowired
    private FileSystemServiceImpl fileSystemService;

    @Autowired
    private FileConfig fileConfig;

    @Override
    public Mono<ResponseData> singleUpload(Mono<FilePart> file) {
        String path = fileConfig.getXUpload();
        return file.flatMap(filePart -> {
            String fileName = filePart.filename();
            fileName = path + UUID.randomUUID() + fileName;
            System.out.println(fileName);
            String finalFileName = fileName;
            DataBufferUtils.join(filePart.content()).flatMap(dataBuffer -> {
                final InputStream inputStream = dataBuffer.asInputStream();
                try {
                    fileSystemService.uploadFile(finalFileName, inputStream);
                } catch (Exception e) {
                    e.getMessage();
                    return Mono.just(ResponseData.fail(ErrorMsgEnum.UPLOAD_ERROR.getCode(),ErrorMsgEnum.UPLOAD_ERROR.getMsg()));
                }
                return Mono.just(ResponseData.ok());
            }).subscribe();
            return Mono.just(ResponseData.ok(finalFileName));
        });
    }

    @Override
    public Mono<ResponseData> moreUpload(Flux<FilePart> file) {
        String path = fileConfig.getXUpload();
        return file.map(filePart -> {
            String fileName = filePart.filename();
            fileName = path + UUID.randomUUID() + fileName;
            System.out.println(fileName);
            String finalFileName = fileName;
            DataBufferUtils.join(filePart.content()).flatMap(dataBuffer -> {
                final InputStream inputStream = dataBuffer.asInputStream();
                try {
                    fileSystemService.uploadFile(finalFileName, inputStream);
                } catch (Exception e) {
                    e.getMessage();
                    return Mono.just(ResponseData.fail(ErrorMsgEnum.UPLOAD_ERROR.getCode(),ErrorMsgEnum.UPLOAD_ERROR.getMsg()));
                }
                return Mono.just(finalFileName);
            }).subscribe();
            return finalFileName;
        }).collectList().flatMap(map ->{
            // 对上传路径的封装
            return Mono.just(ResponseData.ok(map));
        });
    }

    @Override
    public Mono<Void> download(String fileName, ServerHttpResponse response) {
        String path = fileConfig.getXUpload();
        String fileNames = path + fileName;
        return Mono.fromCallable(() -> {
            File file =fileSystemService.downloadFile(fileNames);
            return file;
        }).flatMap(file -> downloadFile(response, file, fileName));
    }
    private Mono<Void> downloadFile(ServerHttpResponse response, File file, String fileName) {
        ZeroCopyHttpOutputMessage zeroCopyResponse = (ZeroCopyHttpOutputMessage) response;
        try {
            response.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
            response.getHeaders()
                    .set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=".concat(
                            URLEncoder.encode(fileName, StandardCharsets.UTF_8.displayName())));

            return zeroCopyResponse.writeWith(file, 0, file.length());
        } catch (UnsupportedEncodingException e) {
            throw new UnsupportedOperationException();
        }
    }
}
